Source code for hysop.backend.device.opencl.operator.derivative

# Copyright (c) HySoP 2011-2024
#
# This file is part of HySoP software.
# See "https://particle_methods.gricad-pages.univ-grenoble-alpes.fr/hysop-doc/"
# for further info.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.


import sympy as sm

from hysop.symbolic import space_symbols
from hysop.symbolic.complex import ComplexMul
from hysop.constants import DirectionLabels
from hysop.backend.device.opencl.opencl_array_backend import OpenClArrayBackend
from hysop.tools.decorators import debug
from hysop.tools.htypes import check_instance
from hysop.tools.numpywrappers import npw
from hysop.core.memory.memory_request import MemoryRequest
from hysop.backend.device.opencl.opencl_operator import OpenClOperator, op_apply
from hysop.backend.device.opencl.opencl_symbolic import OpenClSymbolic
from hysop.backend.device.opencl.autotunable_kernels.custom_symbolic import (
    OpenClAutotunableCustomSymbolicKernel,
)
from hysop.backend.device.opencl.opencl_kernel_launcher import OpenClKernelListLauncher
from hysop.backend.device.opencl.opencl_copy_kernel_launchers import (
    OpenClCopyBufferRectLauncher,
)

from hysop.operator.base.derivative import (
    FiniteDifferencesSpaceDerivativeBase,
    SpectralSpaceDerivativeBase,
)
from hysop.operator.base.custom_symbolic_operator import SymbolicExpressionParser
from hysop.symbolic.relational import Assignment


[docs] class OpenClFiniteDifferencesSpaceDerivative( FiniteDifferencesSpaceDerivativeBase, OpenClSymbolic ): @debug def __new__(cls, **kwds): return super().__new__(cls, require_tmp=False, **kwds) @debug def __init__(self, **kwds): super().__init__(require_tmp=False, **kwds) Fin = self.Fin.s() Fout = self.Fout.s() A = self.A if self.scale_by_field: A = A.s() elif self.scale_by_parameter: if A.size > 1: raise NotImplementedError else: A = A.s xd = space_symbols[self.direction] expr = Assignment(Fout, A * Fin.diff(xd, self.directional_derivative)) self.require_symbolic_kernel("compute_derivative", expr)
[docs] @debug def setup(self, work): super().setup(work) (self.kernel, self.update_parameters) = self.symbolic_kernels[ "compute_derivative" ]
@op_apply def apply(self, **kwds): queue = self.cl_env.default_queue evt = self.kernel(queue=queue, **self.update_parameters()) evt = self.dFout.exchange_ghosts(queue=queue, evt=evt)
[docs] class OpenClSpectralSpaceDerivative(SpectralSpaceDerivativeBase, OpenClSymbolic): """ Compute a derivative of a scalar field in a given direction using spectral methods. """ @debug def __new__(cls, **kwds): return super().__new__(cls, **kwds) @debug def __init__(self, **kwds): """ Initialize a SpectralSpaceDerivative operator on the opencl backend. See hysop.operator.base.derivative.SpectralSpaceDerivativeBase for more information. Parameters ---------- kwds: dict, optional Base class arguments. """ super().__init__(**kwds) Fs = self.Fin.s() dFs = self.Fout.s() Fhs = self.Ft.output_symbolic_array("Fhat") if self.scale_by_field: As = A.s() elif self.scale_by_parameter: if A.size > 1: raise NotImplementedError else: As = A.s elif self.scale_by_value: As = A else: As = None if As is not None: assert self.scale_by_value or self.scale_by_parameter or self.scale_by_field expr = Assignment(Fout, As * Fout) self.require_symbolic_kernel("scale_derivative", expr) self._do_scale = True else: self._do_scale = False Kr = 1 Kc = None for wn, indexed_wn in self.tg._indexed_wave_numbers.items(): if wn.is_real: Kr *= indexed_wn else: assert wn.is_complex if Kc is None: Kc = indexed_wn else: Kc = ComplexMul(Kc, indexed_wn) if Kc is None: rhs = Kr * Fhs else: rhs = Kr * ComplexMul(Kc, Fhs) expr = Assignment(Fhs, rhs) self.require_symbolic_kernel("compute_derivative", expr) self.Fhs = Fhs
[docs] @debug def discretize(self, **kwds): super().discretize(**kwds)
[docs] @debug def setup(self, work): super().setup(work=work) if self._do_scale: (self.scale_kernel, self.scale_update_parameters) = self.symbolic_kernels[ "scale_derivative" ] else: self.scale_derivative_kernel = lambda **kwds: None self.scale_update_parameters = lambda: {} self.compute_derivative_kernel, _ = self.symbolic_kernels["compute_derivative"]
@op_apply def apply(self, **kwds): queue = self.cl_env.default_queue self.Ft() self.compute_derivative_kernel(queue=queue) self.Bt() self.scale_derivative_kernel(queue=queue, **self.scale_update_parameters()) self.dFout.exchange_ghosts()